package com.stars.easyms.schedule.util;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 *  日期(date、timestamp)工具类
 *
 * @author guoguifang
 */
public final class DateUtil {

    public final static String FORMAT_yyyy_MM_dd = "yyyy-MM-dd";

    public final static String FORMAT_yyyyMMdd = "yyyyMMdd";

    public final static String FORMAT_yyyyMM = "yyyyMM";

    public final static String FORMAT_yyyy_MM = "yyyy-MM";

    public final static String FORMAT_yyyy = "yyyy";

    public final static String FORMAT_MM = "MM";

    public final static String FORMAT_dd = "dd";

    public final static String FORMAT_yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";

    public final static String FORMAT_yyyyMMddHHmmSS = "yyyyMMddHHmmss";

    public final static String FORMAT_yyyy_MM_dd_HH_mm_ss_SSS = "yyyy-MM-dd HH:mm:ss.SSS";

    public final static String FORMAT_HH_mm_ss = "HH:mm:ss";

    public static final int USE_YEAR = 1;

    public static final int USE_MONTH = 2;

    public static final int USE_DAY = 3;

    /**
     * * 得到几天前的时间
     * *
     * * @param d
     * * @param day
     * * @return
     * */
    public static Date getDateBefore(Date d, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(d);
        now.set(Calendar.DATE, now.get(Calendar.DATE) - day);
        return now.getTime();
    }
    /**
     * 得到自定义格式的日期字符串
     */
    public static String getDateStr(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * 得到格式为"yyyy-MM-dd HH:mm:ss"的日期字符串
     */
    public static String getDateStr(Date date) {
        if (date == null) {
            return null;
        }

        return getDateStr(date, FORMAT_yyyy_MM_dd_HH_mm_ss);
    }
    /**
     * 得到格式为"yyyy-MM-dd"的日期字符串
     */
    public static String getDateStr2(Date date) {
        if (date == null) {
            return null;
        }

        return getDateStr(date, FORMAT_yyyy_MM_dd);
    }
    /**
     * 得到自定义格式的日期类型
     */
    public static Date getDate(String dateStr, String pattern) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.parse(dateStr);
    }

    /**
     * 得到自定义格式的日期类型
     */
    public static Timestamp getTimestamp(String dateStr, String pattern) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        Date date = sdf.parse(dateStr);
        return new Timestamp(date.getTime());
    }

    /**
     * 得到自定义格式的当前日期
     */
    public static String getCurrentDateStr(String pattern) {
        return getDateStr(new Date(), pattern);
    }

    /**
     * 得到格式为"yyyy-MM-dd"的当前日期
     */
    public static String getCurrentDateStr1() {
        return getCurrentDateStr(FORMAT_yyyy_MM_dd);
    }

    /**
     * 得到格式为"yyyy/MM/dd"的当前日期
     */
    public static String getCurrentDateStr2() {
        return getCurrentDateStr("yyyy/MM/dd");
    }

    public static String getDateStrByMilliSecond(Date date) {
        return getDateStr(date, FORMAT_yyyy_MM_dd_HH_mm_ss_SSS);
    }

    /**
     * 得到格式为"yyyy-MM-dd HH:mm:ss"的日期类型
     */
    public static Date getDateFormat(String dateStr) throws ParseException {
        return getDate(dateStr, FORMAT_yyyy_MM_dd_HH_mm_ss);
    }

    /**
     * 得到格式为"yyyy-MM-dd HH:mm:ss"的日期类型
     */
    public static Timestamp getTimestampFormat(String dateStr) throws ParseException {
        return getTimestamp(dateStr, FORMAT_yyyy_MM_dd_HH_mm_ss);
    }

    /**
     * 得到格式为"yyyy-MM-dd HH:mm:ss,SSS"的日期类型
     */
    public static Date getDateByMillisecond(String dateStr) throws ParseException {
        return getDate(dateStr, FORMAT_yyyy_MM_dd_HH_mm_ss_SSS);
    }

    /**
     * 得到格式为"yyyy-MM-dd HH:mm:ss,SSS"的日期字符串
     */
    public static String getDateStrByMillisecond(Date date) {
        return getDateStr(date, FORMAT_yyyy_MM_dd_HH_mm_ss_SSS);
    }

    private static final int[] DAY_ARRAY = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    /**
     * 取得指定日期的所处月份的最后一天
     *
     * @param date 指定日期。
     * @return 指定日期的所处月份的最后一天
     */
    public static Date getLastDayOfMonth(Date date) {
        /**
         * 详细设计：0.如果date在闰年的2月，则为29日 1.如果date在1月，则为31日 2.如果date在2月，则为28日 3.如果date在3月，则为31日
         * 4.如果date在4月，则为30日 5.如果date在5月，则为31日 6.如果date在6月，则为30日
         * 7.如果date在7月，则为31日 8.如果date在8月，则为31日 9.如果date在9月，则为30日
         * 10.如果date在10月，则为31日 11.如果date在11月，则为30日 12.如果date在12月，则为31日
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        // 检查闰年
        if ((gc.get(Calendar.MONTH) == Calendar.FEBRUARY) && (isLeapYear(gc.get(Calendar.YEAR)))) {
            gc.set(Calendar.DAY_OF_MONTH, 29);
        } else {
            gc.set(Calendar.DAY_OF_MONTH, DAY_ARRAY[gc.get(Calendar.MONTH)]);
        }
        return gc.getTime();
    }

    /**
     * 取得指定日期的所处月份的第一天
     *
     * @param date 指定日期。
     * @return 指定日期的所处月份的第一天
     */
    public static Date getFirstDayOfMonth(Date date) {
        /**
         * 详细设计：设置为1号
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.set(Calendar.DAY_OF_MONTH, 1);
        return gc.getTime();
    }

    /**
     * 得到指定日期的前一个工作日
     */
    public static Date getPreviousWeekDay(Date date) {
        /**
         * 详细设计： 1.如果date是星期日，则减3天 2.如果date是星期六，则减2天 3.否则减1天
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        switch (gc.get(Calendar.DAY_OF_WEEK)) {
            case (Calendar.MONDAY):
                gc.add(Calendar.DATE, -3);
                break;
            case (Calendar.SUNDAY):
                gc.add(Calendar.DATE, -2);
                break;
            default:
                gc.add(Calendar.DATE, -1);
                break;
        }
        return gc.getTime();
    }

    /**
     * 得到指定日期的后一个工作日
     */
    public static Date getNextWeekDay(Date date) {
        /**
         * 详细设计： 1.如果date是星期五，则加3天 2.如果date是星期六，则加2天 3.否则加1天
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        switch (gc.get(Calendar.DAY_OF_WEEK)) {
            case (Calendar.FRIDAY):
                gc.add(Calendar.DATE, 3);
                break;
            case (Calendar.SATURDAY):
                gc.add(Calendar.DATE, 2);
                break;
            default:
                gc.add(Calendar.DATE, 1);
                break;
        }
        return gc.getTime();
    }

    /**
     * 取得指定日期的后N个月(前N个月为负数)
     */
    public static Date getNMonth(Date date, int n) {
        /**
         * 详细设计： 1.指定日期的月份减1
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.add(Calendar.MONTH, n);
        return gc.getTime();
    }

    /**
     * 取得指定日期的前一个月
     */
    public static Date getPreMonth(Date date) {
        return getNMonth(date, -1);
    }

    /**
     * 取得指定日期的下一个月
     */
    public static Date getNextMonth(Date date) {
        return getNMonth(date, 1);
    }

    /**
     * 返回指定的日期加上N天
     */
    public static Date getNDay(Date date, int day) {
        /**
         * 详细设计： 指定日期加N天
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.add(Calendar.DATE, day);
        return gc.getTime();
    }

    /**
     * 获取指定日期的前一天
     */
    public static Date getPreDay(Date date) {
        return getNDay(date, -1);
    }

    /**
     * 取得指定日期的下一天
     */
    public static Date getNextDay(Date date) {
        return getNDay(date, 1);
    }

    /**
     * 取得指定日期的下一个月的第一天
     */
    public static Date getFirstDayOfNextMonth(Date date) {
        /**
         * 详细设计： 1.调用getNextMonth设置当前时间 2.以1为基础，调用getFirstDayOfMonth
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.setTime(DateUtil.getNextMonth(gc.getTime()));
        gc.setTime(DateUtil.getFirstDayOfMonth(gc.getTime()));
        return gc.getTime();
    }

    /**
     * 取得指定日期的下一个月的最后一天
     */
    public static Date getLastDayOfNextMonth(Date date) {
        /**
         * 详细设计： 1.调用getNextMonth设置当前时间 2.以1为基础，调用getLastDayOfMonth
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.setTime(getNextMonth(gc.getTime()));
        gc.setTime(getLastDayOfMonth(gc.getTime()));
        return gc.getTime();
    }

    /**
     * 取得指定日期的下一个星期的第一天
     */
    public static Date getFirstDayOfNextWeek(Date date) {
        /**
         * 详细设计： 1.调用getNextWeek设置当前时间 2.以1为基础，调用getFirstDayOfWeek
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.setTime(DateUtil.getNextWeek(gc.getTime()));
        gc.setTime(DateUtil.getFirstDayOfWeek(gc.getTime()));
        return gc.getTime();
    }

    /**
     * 取得指定日期的下一个星期的最后一天
     */
    public static Date getLastDayOfNextWeek(Date date) {
        /**
         * 详细设计： 1.调用getNextWeek设置当前时间 2.以1为基础，调用getLastDayOfWeek
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.setTime(DateUtil.getNextWeek(gc.getTime()));
        gc.setTime(DateUtil.getLastDayOfWeek(gc.getTime()));
        return gc.getTime();
    }

    /**
     * 取得指定日期的下一个星期
     */
    public static Date getNextWeek(Date date) {
        /**
         * 详细设计： 1.指定日期加7天
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.add(Calendar.DATE, 7);
        return gc.getTime();
    }

    /**
     * 取得指定日期的所处星期的最后一天
     */
    public static Date getLastDayOfWeek(Date date) {
        /**
         * 详细设计： 1.如果date是星期日，则加6天 2.如果date是星期一，则加5天 3.如果date是星期二，则加4天
         * 4.如果date是星期三，则加3天 5.如果date是星期四，则加2天 6.如果date是星期五，则加1天
         * 7.如果date是星期六，则加0天
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        switch (gc.get(Calendar.DAY_OF_WEEK)) {
            case (Calendar.SUNDAY):
                gc.add(Calendar.DATE, 6);
                break;
            case (Calendar.MONDAY):
                gc.add(Calendar.DATE, 5);
                break;
            case (Calendar.TUESDAY):
                gc.add(Calendar.DATE, 4);
                break;
            case (Calendar.WEDNESDAY):
                gc.add(Calendar.DATE, 3);
                break;
            case (Calendar.THURSDAY):
                gc.add(Calendar.DATE, 2);
                break;
            case (Calendar.FRIDAY):
                gc.add(Calendar.DATE, 1);
                break;
            case (Calendar.SATURDAY):
                gc.add(Calendar.DATE, 0);
                break;
            default:
                gc.add(Calendar.DATE, 6);
        }
        return gc.getTime();
    }

    /**
     * 取得指定日期的所处星期的第一天
     */
    public static Date getFirstDayOfWeek(Date date) {
        /**
         * 详细设计： 1.如果date是星期日，则减0天 2.如果date是星期一，则减1天 3.如果date是星期二，则减2天
         * 4.如果date是星期三，则减3天 5.如果date是星期四，则减4天 6.如果date是星期五，则减5天
         * 7.如果date是星期六，则减6天
         */
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        switch (gc.get(Calendar.DAY_OF_WEEK)) {
            case (Calendar.SUNDAY):
                gc.add(Calendar.DATE, 0);
                break;
            case (Calendar.MONDAY):
                gc.add(Calendar.DATE, -1);
                break;
            case (Calendar.TUESDAY):
                gc.add(Calendar.DATE, -2);
                break;
            case (Calendar.WEDNESDAY):
                gc.add(Calendar.DATE, -3);
                break;
            case (Calendar.THURSDAY):
                gc.add(Calendar.DATE, -4);
                break;
            case (Calendar.FRIDAY):
                gc.add(Calendar.DATE, -5);
                break;
            case (Calendar.SATURDAY):
                gc.add(Calendar.DATE, -6);
                break;
            default:
                gc.add(Calendar.DATE, 0);
        }
        return gc.getTime();
    }

    /**
     * 计算两个日期之间的天数
     */
    public static int getBetweenDays(Date startDate, Date endDate) {
        long i = startDate.getTime() - endDate.getTime();
        return (int) (i / (60 * 60 * 1000 * 24));
    }

    /**
     * 判断指定年份是否是闰年
     */
    public static boolean isLeapYear(int year) {
        /**
         * 详细设计： 1.被400整除是闰年，否则： 2.不能被4整除则不是闰年 3.能被4整除同时不能被100整除则是闰年
         * 3.能被4整除同时能被100整除则不是闰年
         */
        return (year % 400) == 0 || (year % 4) == 0 && (year % 100) != 0;
    }

    /**
     * 判断指定日期的年份是否是闰年
     */
    public static boolean isLeapYear(Date date) {
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        int year = gc.get(Calendar.YEAR);
        return isLeapYear(year);
    }

    private DateUtil(){}
}
